﻿using GalaSoft.MvvmLight.Messaging;
using System;
using System.Threading.Tasks;
using VisionApp.Interface;
using VisionApp.Entity;
using System.Threading;
using GalaSoft.MvvmLight;
using System.Collections;
using LiveCharts;
using System.Collections.Generic;
using System.Linq;
using CommonServiceLocator;
using VisionAppManager.ViewModel;
using System.Windows.Forms;
using Autofac;
using System.IO;
using OpenCvSharp;
using System.Timers;
using System.Configuration;
using System.Net.Sockets;
using System.Net;
using System.Linq.Expressions;

namespace VisionAppManager.Model
{
    public class Worker : ObservableObject, IWorker, IDisposable
    {
        private CfgIO _cfg;
        private RobDataContainer _robRC;
        public Logger _log;
        private int _imgTrigID = 1;
        private object _runLock = new object();
        public PictureBox PBVideoLeft { get; set; }
        public PictureBox PBVideoRight { get; set; }
        public PictureBox PBImageLeft { get; set; }
        public PictureBox PBImageRight { get; set; }
        public CameraModel Camera { get; set; }
        public VisionModel Vision { get; set; }
        public RobotModel Robot { get; set; }
        private bool _manualMode = false;
        public bool ManualMode
        {
            get
            {
                return _manualMode;
            }
            set
            {
                Set<bool>(ref _manualMode, value);
                if (ManualMode)
                {
                    StartRecordEnabled = true;
                    StopRecordEnabled = false;
                }
                else
                {
                    StartRecordEnabled = false;
                    StopRecordEnabled = false;
                }
            }
        }
        private bool _running = false;
        private bool _stopping = false;
        public bool Running
        {
            get
            {
                return _running;
            }
            set
            {
                Set<bool>(ref _running, value);
                Stopped = !_running;
                Color = _running ? "Lime" : "Gray";
            }
        }
        private bool _stopped = true;
        public bool Stopped
        {
            get
            {
                return _stopped;
            }
            set
            {
                Set<bool>(ref _stopped, value);
            }
        }
        private bool _startRecordEnabled = false;
        public bool StartRecordEnabled
        {
            get
            {
                return _startRecordEnabled;
            }
            set
            {
                Set<bool>(ref _startRecordEnabled, value);
            }
        }
        private bool _stopRecordEnabled = false;
        public bool StopRecordEnabled
        {
            get
            {
                return _stopRecordEnabled;
            }
            set
            {
                Set<bool>(ref _stopRecordEnabled, value);
            }
        }
        private string _color = "Gray";
        public string Color
        {
            get
            {
                return _color;
            }
            set
            {
                Set<string>(ref _color, value);
            }
        }
        public string HelpText { get; set; } = "机器人指令：\r\n" +
                                               "视频模式：\r\n" +
                                               "    1.发送条码信息：9,xxxxxxx 无条码默认以时间储存视频：9,0000\r\n" +
                                               "    2.开始监控：1\r\n" +
                                               "    3.结束监控：2\r\n" +
                                               "图像模式：\r\n" +
                                               "    1.发送条码信息：9,xxxxxxx 无条码默认以时间储存照片：9,0000\r\n" +
                                               "    2.指定相机编号：3,x 其中x为1表示1号相机，2表示2号相机\r\n" +
                                               "    3.开始拍照：1\r\n" +
                                               "    4.中间切换相机编号：3,x 其中x为1表示1号相机，2表示2号相机\r\n" +
                                               "    5.结束拍照：2\r\n";
        public ChartValues<int> ChartValues { get; set; }
        private Statistic _statistic;
        public Statistic Statistic
        {
            get
            {
                return _statistic;
            }
            set
            {
                Set<Statistic>(ref _statistic, value);
            }
        }
        private System.Timers.Timer _timer = null;
        public Worker()
        {
            _log = new Logger();
            _cfg = new CfgIO();
            Camera = new CameraModel(_log, _cfg);
            Robot = new RobotModel(_log, _cfg);
            Vision = new VisionModel(_log, _cfg);
            ChartValues = new ChartValues<int>();
            _cfg.Load("Statistic", ref _statistic);
            if (_statistic == null)
            {
                _statistic = new Statistic();
                _cfg.Save("Statistic", _statistic);
            }
            Messenger.Default.Register<RobDataMediaType>(this, (rc) => robDataRecv(rc));
            _timer = new System.Timers.Timer();
            _timer.Elapsed += _timer_Elapsed;

            // 启动IP地址变更检测任务
            CameraMgr.GetInstance(_statistic).start();
            Thread.Sleep(2000);
        }

        private void startTimer()
        {
            _timer.Interval = Convert.ToUInt32(ConfigurationManager.AppSettings["TimeOut"]) * 1000;
            _timer.Enabled = true;
            _timer.AutoReset = true;
            _timer.Start();
        }
        private void stopTimer()
        {
            _timer.Stop();
            _timer.Close();
        }
        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _log.Imformation("录像已超时，将停止！");
            StopRecordProc1();
        }

        public int Init()
        {
            if (!Camera.Connected)
            {
                if (Camera.Init() != 0)
                {
                    return -1;
                }
            }
            if (!Robot.Connected)
            {
                int ret = Robot.Init();
                if (ret != 0)
                {
                    return -1;
                }
            }
            if (!Vision.Connected)
            {
                if (Vision.Init() != 0)
                {
                    return -1;
                }
            }
            if (ManualMode)
            {
                StartRecordEnabled = true;
                StopRecordEnabled = false;
            }

            return 0;
        }
        public async Task Exit()
        {
            await Task.Run(() =>
            {
                if (Camera.Close() != 0)
                {
                    return;
                }
                if (Robot.Connected)
                {
                    if (Robot.Close() != 0)
                    {
                        return;
                    }
                }
                StartRecordEnabled = true;
                StopRecordEnabled = false;
            });
        }
        public void SaveCfgData()
        {
            Camera.SaveCfg();
            Robot.SaveCfg();
            Vision.SaveCfg();
        }
        public void Dispose()
        {
            Messenger.Default.Unregister<RobDataMediaType>(this, (rc) => robDataRecv(rc));
        }
        public async Task RunRecordProc1()
        {
            try
            {
                await Task.Run(() =>
                {
                    lock (_runLock)
                    {
                        if (Running) {

                            _log.Error("RunRecordProc1 error:  Record is already running");
                            return;
                        }
                        Running = true;
                        startTimer();
                        if (ManualMode)
                        {
                            StartRecordEnabled = false;
                            StopRecordEnabled = true;
                            if (Camera.CfgData.RecordMode == "Video")
                            {
                                AppEngine.Container.Resolve<MainViewModel>().VMWorkspace = AppEngine.Container.Resolve<VMImgViewer>();
                                Camera.CfgData.RecordPath = Vision.GetRecordPath();
                            }
                            else
                            {
                                Camera.CfgData.ImagePath = Vision.GetImagePath();
                            }
                        }
                        if (Camera.CfgData.RecordMode == "Video")
                        {
                            int ret = Camera.Grab(1);
                            if (ret != 0)
                            {
                                Running = false;
                                stopTimer();
                            }
                            ret = Camera.Grab(2);
                            if (ret != 0)
                            {
                                Running = false;
                                stopTimer();
                            }
                        }
                        else
                        {
                            //int ret = Camera.Grab(_imgTrigID);
                            //if (ret != 0)
                            //{
                            //    Running = false;
                            //}
                        }
                    }
                });
            }
            catch (Exception e)
            {
                _log.Error("RunRecordProc error", e);
            }
        }
        public async Task StopRecordProc1()
        {
            await Task.Run(() =>
            {
                lock (_runLock)
                {
                    if (_stopping) {
                        _log.Error("StopRecordProc1 error:  Record is already stopping");
                        return;
                    }
                    _stopping = true;
                    if (Camera.CfgData.RecordMode == "Video")
                    {
                        Camera.Stop(1);
                        Camera.Stop(2);
                    }
                    else
                    {
                        Camera.Stop(_imgTrigID);
                    }
                    Running = false;
                    if (ManualMode)
                    {
                        StartRecordEnabled = true;
                        StopRecordEnabled = false;
                    }
                    updateChart();
                    stopTimer();
                    _stopping = false;
                }
            });
        }
        public void UpdateVideoHandle(PictureBox left, PictureBox right)
        {
            Camera.SelectedCam.PictureBoxVideoLeft = left;
            Camera.SelectedCam.PictureBoxVideoRight = right;
        }
        public void UpdateImageLHandle(PictureBox left)
        {
            Camera.SelectedCam.PictureBoxImageLeft = left;
        }
        public void UpdateImageRHandle(PictureBox right)
        {
            Camera.SelectedCam.PictureBoxImageRight = right;
        }
        private void setBarCode()
        {
            Vision.SetBarCode(_robRC.Str);
            if (Camera.CfgData.RecordMode == "Video")
            {
                AppEngine.Container.Resolve<MainViewModel>().VMWorkspace = AppEngine.Container.Resolve<VMImgViewer>();
                //ServiceLocator.Current.GetInstance<MainViewModel>().VMWorkspace = ServiceLocator.Current.GetInstance<VMImgViewer>();
                Camera.CfgData.RecordPath = Vision.GetRecordPath();
            }
            else
            {
                Camera.CfgData.ImagePath = Vision.GetImagePath();

            }
        }
        private void setCarModel()
        {
            Vision.SetCarModel((CarModel)(int)_robRC.Data[0]);
        }
        private void switchCamera()
        {
            lock (_runLock)
            {
                _imgTrigID = Convert.ToInt32(_robRC.Data[0]);
                if (_imgTrigID == 1)
                {
                    Camera.Stop(2);
                    Camera.Grab(1);
                    AppEngine.Container.Resolve<MainViewModel>().VMWorkspace = AppEngine.Container.Resolve<VMImgViewerCam1>();
                    //ServiceLocator.Current.GetInstance<MainViewModel>().VMWorkspace = ServiceLocator.Current.GetInstance<VMImgViewerCam1>();
                }
                else
                {
                    Camera.Stop(1);
                    Camera.Grab(2);
                    AppEngine.Container.Resolve<MainViewModel>().VMWorkspace = AppEngine.Container.Resolve<VMImgViewerCam2>();
                    //ServiceLocator.Current.GetInstance<MainViewModel>().VMWorkspace = ServiceLocator.Current.GetInstance<VMImgViewerCam2>();
                }
                _log.Imformation("相机切换为：" + _imgTrigID);
            }
        }
        private void switchRecordMode()
        {
            int id = Convert.ToInt32(_robRC.Data[0]);
            if (id == 1)
            {
                Camera.CfgData.RecordMode = "Video";
            }
            else
            {
                Camera.CfgData.RecordMode = "Image";
            }
            Camera.SaveCfg();
            _log.Imformation("监控模式切换为：" + Camera.CfgData.RecordMode);
        }
        private void updateChart()
        {
            _statistic.TotalCount++;
            _statistic.SucccessRate = string.Format("{0:P1}", 1.0 - (double)_statistic.NGCount / _statistic.TotalCount);
            _statistic.TimeCountDic.Add(DateTime.Now, "1");
            _cfg.Save("Statistic", _statistic);
            ChartValues.Clear();
            for (int i = 0; i < 24; i++)
            {
                var arrays = _statistic.TimeCountDic.Where(x => x.Key.Hour == i && x.Key.Day == DateTime.Now.Day).ToList();
                ChartValues.Add(arrays.Count);
            }
        }
        private async void robDataRecv(RobDataMediaType rc)
        {
            if (ManualMode)
            {
                _log.Imformation("当前为手动模式，指令无效");
                return;
            }
            _robRC = rc.Msg;
            switch (_robRC.Name)
            {
                case RobCmdEnum.Trig:
                    await RunRecordProc1();
                    break;
                case RobCmdEnum.Stop:
                    await StopRecordProc1();
                    break;
                case RobCmdEnum.BarCode:
                    setBarCode();
                    break;
                case RobCmdEnum.CarModel:
                    setCarModel();
                    break;
                case RobCmdEnum.CalPart:
                    switchCamera();
                    break;
                case RobCmdEnum.GetCamOffs:
                    switchRecordMode();
                    break;
                default:
                    break;
            }
        }
    }
    public class Statistic : ObservableObject
    {
        /// <summary>
        /// 本机IP
        /// </summary>
        private String _localIP;
        public String LocalIP
        {
            get
            {
                return _localIP;
            }
            set
            {
                Set<String>(ref _localIP, value);
            }
        }

        /// <summary>
        /// 网关IP
        /// </summary>
        private String _gatewayIP;
        public String GatewayIP
        {
            get
            {
                return _gatewayIP;
            }
            set
            {
                Set<String>(ref _gatewayIP, value);
            }
        }

        /// <summary>
        /// 监听端口
        /// </summary>
        private int _listenPort;
        public int ListenPort
        {
            get
            {
                return _listenPort;
            }
            set
            {
                Set<int>(ref _listenPort, value);
            }
        }
        
        /// <summary>
        /// 运行总次数
        /// </summary>
        private long _totalCount;
        public long TotalCount
        {
            get
            {
                return _totalCount;
            }
            set
            {
                Set<long>(ref _totalCount, value);
            }
        }
        /// <summary>
        /// 运行失败次数
        /// </summary>
        private long _ngCount;
        public long NGCount
        {
            get
            {
                return _ngCount;
            }
            set
            {
                Set<long>(ref _ngCount, value);
            }
        }
        /// <summary>
        /// 运行成功率
        /// </summary>
        private string _succcessRate;
        public string SucccessRate
        {
            get
            {
                return _succcessRate;
            }
            set
            {
                Set<string>(ref _succcessRate, value);
            }
        }
        /// <summary>
        /// 时间戳与运行结果字典集合
        /// </summary>
        public Dictionary<DateTime, string> TimeCountDic { get; set; }
        public Statistic()
        {
            TimeCountDic = new Dictionary<DateTime, string>();
        }
    }
}
